#! /usr/bin/env python
# -*- coding: UTF-8 -*-/**-
# Copyright (C) 2008-2009 Robert Spilleboudt
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# main Gui interface  RCOpen_C
from Tkinter import *
import string,  Calc, os
stickSize=150# size of a Stick and his trims
class Simul():
    #TX simulation with debug
    def __init__(self, parent, mdx, tx, can, modesimul):
        self.sim=Toplevel()
        self.mdx=mdx
        #self.mdxold=None
        self.sim.title("Simul:"+mdx.fichier.selectedModel )
        self.tx=tx
        self.can=can
        self.servos= StringVar() # show the servos as a long text
        self.varlist=[] # sorted list for listbox
        self.varfilter= Entry(self.sim, width=5) #dummy replaced with the real Buttons
        self.varfilter_at_var=IntVar()
        self.modesimul=modesimul #0=autmatic simulation (calc follows any input)
                                                   #1=  sync with the microprocessor, manual calc
        self.varShow_var=IntVar() # 0 = result in msec  1= %
        self.paramshow=IntVar()   # 0 do not show the parameters
        self.paramlist=[]
        self.paramlistboxSelected=""
        
#        def  showParam()    : #show the list of the INIT values (vvar) 
#            self.paramlist=[]
#            for v in self.mdx.vars.values():
#                if v.typeOrig==6:
        def   refresh() :     
            if self.modesimul==0: 
                self.mdx.calc(False ) # recalculation after each change
                if self.mdx.mdxold != None:
                    self.mdx.mdxold.calc(False)
                showvar()  

        def putvar(name, value):
            # each slider change sends a signal here, with the label of the control and the value
            #print name +"  "+str(value)
            #update the variable if defined !
            # if name ="" skip the var
            if name[:5]=="DTRIM":
                self.mdx.dtrim[name]= float(value) #only for this simulator and the digital trims

            if name !="":
                if self.mdx.vars.has_key(name)==True :
                    #print name +"  "+str(value)
                    if self.mdx.vars[name].typeNum ==1:
                        self.mdx.vars[name].val= float(value)
                        if self.mdx.mdxold != None:
                            self.mdx.mdxold.vars[name].val= float(value)
                    else:
                        self.mdx.vars[name].val= bool(value)
                        if self.mdx.mdxold != None:
                            self.mdx.mdxold.vars[name].val= bool(value)
            refresh()
  
            
        def showvar():

            #prepare the edited fields with the results
            t=self.mdx.phase  +" "  # t is the text showing the servos output
            self.varlist=[]                    # this is the listbox with the variables
            self.varlistbox.delete(0, END)
            nl=1 # number lines @V
            for v in mdx.vars.values() :
                if v.typeOrig==1 : #hardware output
                    tv=v.name        # fiff the servo text
                    if v.alias != "": t=t+" ("+v.alias+")"
                    if  self.varShow_var.get()==0:
                        tv=tv+" =%5.2f" % v.val #show the value in msec
                    else:
                        tv=tv+" =%5.0f" % ( (v.val -1.55)/0.0055) +"%" #show the value % as the MC24
                        
                    t=t+"     "+tv
                    if len(t) > 70*nl:
                        t=t+"\n"
                        nl=nl+1
                # fill the listbox with  the filtered variables
                if v.typeOrig==4 or v.typeOrig==6 or v.typeOrig==7: #constant or parameter
                    continue
                if self.paramshow.get()==0 and  v.name[-1:]==":":
                    continue
                if self.varfilter_at_var.get()==1 and (v.typeOrig==0 or v.typeOrig==1 ) :
                    # @ are here not showed
                    continue
                if string.find(v.prt(self.mdx), self.varfilter.get())==0 :
                    if mdx.mdxold ==None :
                        self.varlist.append(v.prt(self.mdx))         # the info over a variable comes from the prt()  
                    else:
                        if self.mdx.mdxold.vars.has_key(v.name) ==True:
                            vold= self.mdx.mdxold.vars[v.name]
                            vtxt="..."
                            if type(vold.val)==type(0.1): 
                                vtxt= "   =%8.2f"%vold.val  
                            self.varlist.append(v.prt(self.mdx)+vtxt)
                    
            self.servos.set(t) 
            self.varlist.sort()
            for v in self.varlist:
                self.varlistbox.insert(END, v) 
            
                
                
        def demi_manche(parent, orient,   txlabels):
            # one direction of a stick# orientation VERTICAL or HORIZONTAL
            # analogTrim, digitalTrim are bool
            # output is a list stick value, analog trim, digital trim
            # txlabels -> class Tx for control                 
            # various slider inputs 
            def mx (x): #the stick
                putvar(txlabels[0], x)
            def tax (x): #the trim
                putvar(txlabels[1], x)
#            def tdx (x):
#                putvar(txlabels[2], x)
            if orient==VERTICAL:  
                sidepack =LEFT
                scale_from=100
                scale_to=-100
            else: 
                sidepack=TOP
                scale_from=-100
                scale_to=+100
            f=LabelFrame(parent,  bd=1, text=txlabels[0]) #width=stickSize, height=stickSize,
            m=Scale(f, from_=scale_from, to=scale_to, length=stickSize,  resolution=5, orient=orient, command = mx)
            m.pack(side=sidepack)
            if len(txlabels[1])>0:
                ta = Scale(f, from_=scale_from, to=scale_to, length=stickSize*0.5,  resolution=5, orient=orient, command = tax)
                ta.pack(side=sidepack)
#            if len(txlabels[2])>0:
#                td = Scale(f, from_=-100, to=+100, length=stickSize*0.5,  resolution=5, fg='red', orient=orient,  command = tdx)
#                td.pack(side=sidepack)
            f.pack()
        
        # frame TX_Sticks   with the sticks and cursors
        TX_Sticks = LabelFrame(self.sim, text="Transmitter sticks and cursors")
        # left stick
        St_Left= Frame(TX_Sticks)
        St_Left.pack(side=LEFT)
        demi_manche(St_Left, VERTICAL, tx.manches[2])
        demi_manche(St_Left, HORIZONTAL, tx.manches[3])
        
        def cursor(parent, txlabel):
            def tcursor(x):
                putvar(txlabel, x)
                
            c= Scale(Cursors, from_=100, to=-100, length=stickSize,  resolution=5, label=txlabel, command=tcursor)
            c.pack(side=LEFT)
        # central frame with the cursors and switches
        Central = Frame(TX_Sticks)
        Central.pack(side=LEFT)
        Cursors=Frame(Central)   
        Cursors.pack()
        for c in tx.cursors:
            cursor(Cursors, c)      
        # frame with the switches
        Swframe=LabelFrame(Central,  text= "Switches ") 
        # 2 position switches
        def switch2(parent, txlabel):
            v=IntVar()
            def tswitch():
                putvar(txlabel, v.get())
            c = Checkbutton(  Swframe, text=txlabel,  variable=v, command=tswitch)
            c.pack(side=LEFT)
        for s in tx.sw:
            switch2(Swframe, s)
 
 # 3 position switches
        def switch3(parent, txlabel):
            f=Frame(parent)
            f.pack(side=LEFT)
            v=IntVar()
            v.set(0)
            def t3():
                i=v.get()
                if i==1:
                    putvar(txlabel+"a", 1)
                    putvar(txlabel+"b", 0)
                if i==0:
                    putvar(txlabel+"a", 0)
                    putvar(txlabel+"b", 0)
                if i==2:
                    putvar(txlabel+"a", 0)
                    putvar(txlabel+"b", 1)
            Radiobutton(f, text=txlabel+"a", variable=v, value=1, command=t3).pack(anchor=W)
            Radiobutton(f,  variable=v, value=0, command=t3).pack(anchor=W)
            Radiobutton(f, text=txlabel+"b", variable=v, value=2, command=t3).pack(anchor=W)
        for s in tx.sw3:
            switch3(Swframe, s)
        Swframe.pack()
        
        # right stick
        St_Right= Frame(TX_Sticks)
        St_Right.pack(side=LEFT)
        demi_manche(St_Right, VERTICAL, tx.manches[0])
        demi_manche(St_Right, HORIZONTAL, tx.manches[1])
        TX_Sticks.pack()       
        # output (servo)
        Servos=Frame(self.sim )
        z=Label(Servos,  textvariable=self.servos)  
        z.pack()
        Servos.pack()
        #variables 
        variables=Frame(self.sim) #frame with listbox variables, listbox params and slider param update
        # listbox with the variables
        vardebug=Frame(variables) 
        scrollbar = Scrollbar(vardebug)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.varlistbox = Listbox(vardebug, yscrollcommand=scrollbar.set,  width=60, height=15, font="Courier 10")
        for v in (self.mdx.vars.values()):
            self.varlistbox.insert(END, v.prt(self.mdx))
        self.varlistbox.pack(side=LEFT, fill=BOTH)
        scrollbar.config(command=self.varlistbox.yview)
        vardebug.pack(side=LEFT, fill=Y)
      
      #slider to update the selected param in the listbox
        paramupdate=Frame(variables)
        def tparam(x):
            if self.mdx.vars.has_key("INIT_"+self.paramlistboxSelected):
                self.mdx.vars ["INIT_"+self.paramlistboxSelected].val=float(x)
                #print "New value for "+self.paramlistboxSelected+"  = "+str(x) + "  "+str(self.mdx.vars ["INIT_"+self.paramlistboxSelected].val)
                refresh()
        paramupdateSlider= Scale(paramupdate, from_=100, to=-100, length=30,  resolution=1, orient=VERTICAL,  command=tparam)
        paramupdateSlider.pack(side=LEFT, fill=Y)
        paramupdate.pack(side=LEFT, fill=Y)
       
        #listbox with the params
        def getSelectedParam(event):
            index = self.paramlistbox.curselection()[0]
            self.paramlistboxSelected=self.paramlistbox.get(index) #name of the selected index
            paramupdateSlider.set(self.mdx.vars ["INIT_"+self.paramlistboxSelected].val)
            #print "Select  : "+self.paramlistboxSelected
        paramdebug=Frame(variables) 
        scrollbar = Scrollbar(paramdebug)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.paramlistbox = Listbox(paramdebug, yscrollcommand=scrollbar.set,  width=30, height=15, font="Courier 10")
        self.paramlist=[]
        for v in (self.mdx.vars.values()):
            if v.name [:5]=="INIT_":
                self.paramlist.append(v.name[5:])
        self.paramlist.sort()
        for v in self.paramlist:
            self.paramlistbox.insert(END, v)
        self.paramlistbox.pack(side=RIGHT, fill=BOTH)
        scrollbar.config(command=self.paramlistbox.yview)
        self.paramlistbox.bind('<ButtonRelease-1>', getSelectedParam)
        paramdebug.pack(side=LEFT, fill=Y)
            
  
        variables.pack()
        # ________________________simulation controls__________________________________________________
        Buttons=Frame(self.sim )
        self.varShow_var.set(1)
        varShow_at=Checkbutton(Buttons, text="@V as %",  variable=self.varShow_var)
        varShow_at.pack(side=LEFT)
        
        self.paramshow=IntVar()
        self.paramshow.set(1)
        paramshow=Checkbutton(Buttons, text="param",  variable=self.paramshow)
        paramshow.pack(side=LEFT)
        
        self.varfilter_at_var= IntVar()
        self.varfilter_at_var.set(1)
        varfilter_at=Checkbutton(Buttons, text=" no @ var",  variable=self.varfilter_at_var)
        varfilter_at.pack(side=LEFT)
        
        varfilterlabel=Label(Buttons, text="Variable filter")
        varfilterlabel.pack(side=LEFT)
        self.varfilter= Entry(Buttons, width=5) # no callback  command !
        self.varfilter.pack(side=LEFT)
        def callExit():
            if modesimul==1:
                self.mdx.avrCalc(False)
            self.mdx.export() #save the mdp
            Calc.TRAVEL = False
            self.mdx.open() #reopen without the travel instructions
            self.mdx.export()
            self.sim.destroy()
        
        exit = Button(Buttons, text="Exit", command=callExit)
        exit.pack(side=LEFT) 
        
         
#        def callCalc():
#            self.mdx.avrCalc(True) 
#            self.mdx.calc(True)
#            showvar()
#        if self.modesimul==1: #with microprocessor serial connection
#            if self.mdx.avrLink() == True:
#                self.mdx.avrCalc(True)
#                avrTest=Button(Buttons, text="Calc ", command =callCalc)
#                avrTest.pack(side=LEFT)
#            else:
#                #message
#                print "no connection with micro"""
#                self.sim.destroy()
#                return
#        else: #initial calc
#            self.mdx.calc(True)
#            showvar()
        
  
        def callDebug():
            self.mdx.log.append("Debug")
            self.mdx.calc(True)
            fileDebugName=self.mdx.fichier.getfilename(self.mdx.fichier.selectedModel, "log")
            fileDebug=open(fileDebugName, "w")
            for log in self.mdx.log :
                #print log
                fileDebug.write(log+"\n")
                #t=t+log+"\n"
                #self.can.create_text(20, 20, text=t, anchor=NW,width=780)
            fileDebug.close()
        debug=Button(Buttons, text="Debug", command = callDebug)
        debug.pack(side=LEFT)   
        
        Buttons.pack()   

class Dialog(Toplevel):
    #inspiration # http://effbot.org/tkinterbook/tkinter-dialog-windows.htm
    # dialogue modal
    #cette classe est héritée par chacun des dialogues de l'application
    def __init__(self, parent, data,title = None):
        Toplevel.__init__(self, parent)
        self.transient(parent)
        self.data=data
        if title:
            self.title(title)
        self.parent = parent
        self.result = None
        body = Frame(self)
        self.initial_focus = self.body(body,data)
        body.pack(padx=5, pady=5)
        self.buttonbox()
        self.grab_set()#makes sure that no mouse or keyboard events are sent to the wrong window
        if not self.initial_focus:
            self.initial_focus = self
        self.protocol("WM_DELETE_WINDOW", self.cancel)
        self.geometry("+%d+%d" % (parent.winfo_rootx()+50,                               parent.winfo_rooty()+50))
        self.initial_focus.focus_set()
        self.wait_window(self)

    #
    # construction hooks

    def body(self, master,data):
        # create dialog body.  return widget that should have
        # initial focus.  this method should be overridden

        pass

    def buttonbox(self):
        # add standard button box. override if you don't want the
        # standard buttons
        
        box = Frame(self)
        w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
        w.pack(side=LEFT, padx=5, pady=5)
        w = Button(box, text="Cancel", width=10, command=self.cancel)
        w.pack(side=LEFT, padx=5, pady=5)
        self.bind("&lt;Return>", self.ok)
        self.bind("&lt;Escape>", self.cancel)
        box.pack()
       
        # standard button semantics

    def ok(self, event=None):

        if not self.validate():
            self.initial_focus.focus_set() # put focus back
            
            return

        self.withdraw()
        self.update_idletasks()

        self.apply()

        self.cancel()

    def cancel(self, event=None):

        # put focus back to the parent window
        self.parent.focus_set()
        self.destroy()

        #
        # command hooks

    def validate(self,data):

        return 1 # override

    def apply(self,data):

        pass # override

class SelectModel(Dialog):
    def body(self, master, fichier):
        #self.title="Available models"
        
        self.fichier=fichier
        #self.fichier.open()
        data=fichier.getListModels()
        self.listModels = Listbox(master)
        self.listModels.pack()
        for item in data:
            self.listModels.insert(END, item)
        return self.listModels
    def validate(self):        
        if len(self.listModels.curselection())==1:
            i=int(self.listModels.curselection()[0])
            self.fichier.selectedModel = self.listModels.get(i) #example planeur.ThermikXL
            RCCLinit=open(self.fichier.getfilename("RCCLinit","mdp"), "w")
            RCCLinit.write(self.fichier.selectedModel+'\n')
            RCCLinit.close()
            return 1
        else: return 0
    def apply(self):   
        pass
